#pragma once
#include "reverse_iterator.h"

namespace ly
{
	template<class T>
	struct ListNode
	{
		ListNode(const T& val = T())
			:_val(val)
			,_pPre(nullptr)
			,_pNext(nullptr)
		{}

		ListNode<T>* _pPre;
		ListNode<T>* _pNext;
		T _val;
	};

	template<class T, class Ref, class Ptr>
	class ListIterator
	{
		typedef ListNode<T>* PNode;
		typedef ListIterator<T, Ref, Ptr> Self;

	public:
		ListIterator(PNode pNode = nullptr)
			:_pNode(pNode)
		{}
		
		/*ListIterator(const Self& l)
		{
			PNode tmp(l._pNode);

			swap(tmp->_val, _pNode->_val);
			swap(tmp->_pPre, _pNode->_pPre);
			swap(tmp->_pNext, _pNode->_pNext);
		}*/

		T& operator*()
		{
			return _pNode->_val;
		}

		T* operator->()
		{
			return &(_pNode->_val);
		}

		Self& operator++()
		{
			_pNode = _pNode->_pNext;

			return *this;
		}

		Self operator++(int)
		{
			PNode tmp = *this;
			_pNode = _pNode->_pNext;
			return tmp;
		}

		Self& operator--()
		{
			_pNode = _pNode->_pPre;
			return *this;
		}

		Self operator--(int)
		{
			PNode tmp = *this;
			_pNode = _pNode->_pPre;
			return tmp;
		}

		bool operator!=(const Self& l)
		{
			return _pNode != l._pNode;
		}

		bool operator==(const Self& l)
		{
			return _pNode == l._pNode;
		}

		PNode _pNode;
	};

	template<class T>
	class list
	{
	public:
		typedef ListNode<T> Node;
		typedef Node* PNode;
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;

		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		// construct and destroy
		list()
		{
			CreateHead();
		}

		// list iterator
		iterator begin()
		{
			return _pHead->_pNext;
		}

		iterator end()
		{
			return _pHead;
		}

		const_iterator begin() const
		{
			return _pHead->_pNext;
		}

		const_iterator end() const
		{
			return _pHead;
		}

		// list Modify
		void push_back(const T& val)
		{
			insert(end(), val);
		}

		void pop_back()
		{
			erase(--end());
		}

		void push_front(const T& val)
		{
			insert(begin(), val);
		}

		void pop_front()
		{
			erase(begin());
		}

		iterator insert(iterator pos, const T& val)
		{
			PNode cur = pos._pNode;
			PNode prev = cur->_pPre;
			PNode newnode = new Node;
			newnode->_val = val;

			newnode->_pPre = prev;
			prev->_pNext = newnode;
			newnode->_pNext = cur;
			cur->_pPre = newnode;

			return (iterator)newnode;
		}

		iterator erase(iterator pos)
		{
			iterator prev = pos->_pPre;
			iterator next = pos->_pNext;
			delete pos;

			prev->_pNext = next;
			next->_pPre = prev;

			return next;
		}

		void CreateHead()
		{
			_pHead = new Node;
			_pHead->_pPre = _pHead;
			_pHead->_pNext = _pHead;
		}

	private:
		PNode _pHead;
	};
}
